#pragma once

#include <string>

typedef long long FX64;
typedef int FX32;

#define PI 3.14159265
#define FX32_SHIFT 12
#define FX32_ONE (1 << FX32_SHIFT)
#define FXAdd(a, b) ((a) + (b))
#define FXSub(a, b) ((a) - (b))
#define FXMul(a, b) (FX32)(((FX64)(a) * (FX64)(b)) >> FX32_SHIFT)
#define FXDiv(a, b) (FX32)(((FX64)(a) << FX32_SHIFT) / (FX64)(b))
#define FXFXToInt(a) (int)((a) >> FX32_SHIFT)
#define FXIntToFX(a) (FX32)((a) << FX32_SHIFT)
#define FXFXToFloat(a) (float)((double)(a) / (double)FX32_ONE)
#define FXFloatToFX(a) (FX32)((a) * (float)FX32_ONE)
#define FX32_TABLE_BITS 16
#define FX32_TABLE_SIZE (1 << FX32_TABLE_BITS)
#define FX32_TABLE_MASK (FX32_TABLE_SIZE - 1)

class SCRMath
{
public:

	static const int HASH_PRIME = 1450107;
	static const int HASH_SEED = 164301;

	static void Initialize();
	static unsigned int GetHash(const void* pDataA, const size_t& NumberOfBytes);
	static unsigned int GetHash(const std::string& Text);
	static FX32 FXSin(const int& Angle);
	static FX32 FXCos(const int& Angle);

private:

	static FX32 SinTableA[FX32_TABLE_SIZE];
	static FX32 CosTableA[FX32_TABLE_SIZE];
};

inline unsigned int SCRMath::GetHash(const void* pData, const size_t& NumberOfBytes)
{
	int Hash = HASH_SEED;
	size_t BytesC = NumberOfBytes;
	const unsigned char* pCharData = (const unsigned char*)pData;
	while (BytesC--)
	{
		Hash = (*pCharData++ ^ Hash) * HASH_PRIME;
	}

	return Hash;
}

inline unsigned int SCRMath::GetHash(const std::string& Text)
{
	return GetHash(Text.c_str(), Text.length());
}

inline FX32 SCRMath::FXSin(const int& Angle)
{
	return SinTableA[Angle & FX32_TABLE_MASK];
}

inline FX32 SCRMath::FXCos(const int& Angle)
{
	return CosTableA[Angle & FX32_TABLE_MASK];
}